{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b26658c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "#import the required libraries\n",
    "from tensorflow import keras\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import imageio\n",
    "import cv2\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a38e1b1",
   "metadata": {},
   "source": [
    "## Dataset\n",
    "\n",
    "- We will use the Deepfake Detection Challenge’s sample training data set available on Kaggle \n",
    "  (Deepfake Detection Challenge Data, 2019) at https://www.kaggle.com/c/deepfake-detection-challenge/data.  \n",
    "\n",
    "- This sample data contains 800 video files (real videos and fake videos included) in .mp4 format. \n",
    "\n",
    "- The videos are placed in two folders – training and testing with 400 videos each. \n",
    "\n",
    "- A metadata.json file indicates for each video following four pieces of information – filename of the video file, whether the video is real or fake as its label, if the video is fake then original indicates the name of original video from which the fake was created, and the split is train for all videos in the training folder.\n",
    "\n",
    "\n",
    "## Code\n",
    "\n",
    "- The code you will see below is inspired from the Keras blog on Video classification (Paul, 2021), and these Kaggle Notebooks - DeepFake Starter Kit page at Kaggle (Deepfake Starter Kit, Kaggle, 2020) and (DB, 2022). Both the notebooks were released under the Apache 2.0 Licence (https://www.apache.org/licenses/LICENSE-2.0). \n",
    "\n",
    "- This code was implemented in Jupyter Notebook under Anaconda 3 Python Distribution (Python 3.11.9) on my Windows 11 PC. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "17d659cc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of Train samples: 400\n",
      "Numbrt of Test samples: 400\n"
     ]
    }
   ],
   "source": [
    "#store the path to root folder containing all videos\n",
    "data_dir = 'deepfake-detection-challenge'\n",
    "#store the path to subfolder containing videos we will use for model training\n",
    "train_dir = 'train_sample_videos'\n",
    "#store the path to subfolder containing videos we will use for model testing\n",
    "test_dir = 'test_videos'\n",
    "\n",
    "#print the number of video samples in train and test folders\n",
    "print(f\"Number of Train samples: {len(os.listdir(os.path.join(data_dir, train_dir)))}\")\n",
    "print(f\"Numbrt of Test samples: {len(os.listdir(os.path.join(data_dir, test_dir)))}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "d1b39e83",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>label</th>\n",
       "      <th>split</th>\n",
       "      <th>original</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>aagfhgtpmv.mp4</th>\n",
       "      <td>FAKE</td>\n",
       "      <td>train</td>\n",
       "      <td>vudstovrck.mp4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>aapnvogymq.mp4</th>\n",
       "      <td>FAKE</td>\n",
       "      <td>train</td>\n",
       "      <td>jdubbvfswz.mp4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>abarnvbtwb.mp4</th>\n",
       "      <td>REAL</td>\n",
       "      <td>train</td>\n",
       "      <td>None</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>abofeumbvv.mp4</th>\n",
       "      <td>FAKE</td>\n",
       "      <td>train</td>\n",
       "      <td>atvmxvwyns.mp4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>abqwwspghj.mp4</th>\n",
       "      <td>FAKE</td>\n",
       "      <td>train</td>\n",
       "      <td>qzimuostzz.mp4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               label  split        original\n",
       "aagfhgtpmv.mp4  FAKE  train  vudstovrck.mp4\n",
       "aapnvogymq.mp4  FAKE  train  jdubbvfswz.mp4\n",
       "abarnvbtwb.mp4  REAL  train            None\n",
       "abofeumbvv.mp4  FAKE  train  atvmxvwyns.mp4\n",
       "abqwwspghj.mp4  FAKE  train  qzimuostzz.mp4"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#reading the metadata.json file into a pandas dataframe\n",
    "train_metadata = pd.read_json('deepfake-detection-challenge/metadata.json').T\n",
    "train_metadata.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "1a26c23a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(400, 3)"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_metadata.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "49c0c5d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "#store the names of test videos as a dataframe\n",
    "test_videos = pd.DataFrame(list(os.listdir(os.path.join(data_dir, test_dir))), columns=['video'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dff966ab",
   "metadata": {},
   "source": [
    "## Let us create a CNN model for classification\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "b73e9bf4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# video frame properties and model training hyperparameters\n",
    "#size of each image/video frame, we are using 224x224 pixels images\n",
    "img_size = 224\n",
    "#number of videos used in each training step\n",
    "batch_size = 16\n",
    "#number of epochs of training\n",
    "no_of_epochs = 50\n",
    "\n",
    "#maximum number of video frames considered from each video.\n",
    "#this truncates longer videos and pads shorter ones\n",
    "max_seq_length= 40\n",
    "\n",
    "#number of features extracted from each video frame\n",
    "num_features = 2048"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "779ffa6f",
   "metadata": {},
   "outputs": [],
   "source": [
    "#helper function to crop the center square portion of a video frame\n",
    "def crop_frame_center(frame):\n",
    "    y, x = frame.shape[0:2]#frame dimensions\n",
    "    min_dim = min(y, x)#smaller dimension\n",
    "    start_x = (x // 2) - (min_dim // 2)#starting x coordinate of cropping square\n",
    "    start_y = (y // 2) - (min_dim // 2)#starting x coordinate of cropping square\n",
    "    return frame[start_y : start_y + min_dim, start_x : start_x + min_dim]#return cropped area\n",
    "\n",
    "#helper function to load frames of a video located at a specified path \n",
    "#each frame is resized to img_size x img_size \n",
    "def load_video_frames(path, max_frames=0, resize=(img_size, img_size)):\n",
    "    cap = cv2.VideoCapture(path)#open a video using OpenCV\n",
    "    frames = []\n",
    "    try:\n",
    "        while True:\n",
    "            ret, frame = cap.read()#read a frame\n",
    "            if not ret:\n",
    "                break\n",
    "            frame = crop_frame_center(frame)#crop center square from the frame\n",
    "            frame = cv2.resize(frame, resize)#resize the cropped region\n",
    "            frame = frame[:, :, [2, 1, 0]]#reorder the color channels to RGB\n",
    "            frames.append(frame)#append the frame to frames list\n",
    "\n",
    "            if len(frames) == max_frames:#if max number of frames have been processed, break\n",
    "                break\n",
    "    finally:\n",
    "        cap.release() #release video capture\n",
    "    return np.array(frames) #return a numpy arrray of video frames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "02b8a09d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#helper function to extract features from each video using InceptionV3 model\n",
    "def extract_video_features():\n",
    "    \"\"\"\n",
    "    This function defines and builds a pre-trained feature extractor model \n",
    "    using InceptionV3 architecture.\n",
    "\n",
    "    Returns:\n",
    "    A compiled Keras model for feature extraction.\n",
    "    \"\"\"\n",
    "    # Load the InceptionV3 model pre-trained on ImageNet dataset\n",
    "    feature_extractor = keras.applications.InceptionV3(\n",
    "      weights=\"imagenet\",  # Load pre-trained weights from imagenet for feature extraction\n",
    "      include_top=False,  # Exclude the classification layers (we only need features)\n",
    "      pooling=\"avg\",      # Use average pooling for feature representation\n",
    "      input_shape=(img_size, img_size, 3),# Specify the input shape of the video frames 224x224x3\n",
    "    )\n",
    "\n",
    "    # Access the pre-processing function for InceptionV3\n",
    "    preprocess_input = keras.applications.inception_v3.preprocess_input\n",
    "\n",
    "    # Define the model input layer\n",
    "    inputs = keras.Input((img_size, img_size, 3))\n",
    "\n",
    "    # Preprocess the input using the InceptionV3 function preprocess_input()\n",
    "    preprocessed = preprocess_input(inputs)\n",
    "\n",
    "    # Extract features using the pre-trained InceptionV3 model\n",
    "    outputs = feature_extractor(preprocessed)\n",
    "\n",
    "    # Create a Keras model with the defined inputs and feature extraction outputs\n",
    "    return keras.Model(inputs, outputs, name=\"feature_extractor\")\n",
    "\n",
    "# Call the function to build and instantiate the feature extractor model\n",
    "feature_extractor = extract_video_features()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "a0406940",
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_videos(df, root_dir):\n",
    "    \"\"\"\n",
    "    This function preprocesses and prepares video data for training the model.\n",
    "    Args:\n",
    "      df (pandas.DataFrame): DataFrame containing video information (paths and labels).\n",
    "      root_dir (str): Root directory path containing the video files.\n",
    "    Returns:\n",
    "      tuple: A tuple containing two elements:\n",
    "          - features (numpy.ndarray): A 3D array of video features,shaped (num_samples, max_seq_length, num_features).\n",
    "          - labels (numpy.ndarray): A 1D array of video labels (0 - real, 1 - fake).\n",
    "     \"\"\"\n",
    "    # Get the number of video samples and their paths from the DataFrame\n",
    "    num_samples = len(df)\n",
    "    video_paths = list(df.index)\n",
    "    # Extract labels and convert them to a binary numpy array (0 - real, 1 - fake)\n",
    "    labels = df[\"label\"].values\n",
    "    labels = np.array(labels == 'FAKE').astype(int)\n",
    "    # Initialize arrays to store features and masks for all videos\n",
    "    frame_masks = np.zeros(shape=(num_samples, max_seq_length), dtype=\"bool\")\n",
    "    frame_features = np.zeros(shape=(num_samples, max_seq_length, num_features), dtype=\"float32\")\n",
    "    # Process each video in the DataFrame\n",
    "    for idx, path in enumerate(video_paths):\n",
    "        # Load all frames from the video and add a batch dimension\n",
    "        frames = load_video_frames(os.path.join(root_dir, path))\n",
    "        frames = frames[None, ...]  # Add batch dimension\n",
    "        # Initialize temporary arrays for features and masks of the current video\n",
    "        temp_frame_mask = np.zeros(shape=(1, max_seq_length,), dtype=\"bool\")\n",
    "        temp_frame_features = np.zeros(shape=(1, max_seq_length, num_features), dtype=\"float32\")\n",
    "        # Extract features for each frame in the video\n",
    "        for i, batch in enumerate(frames):\n",
    "            video_length = batch.shape[0]\n",
    "            length = min(max_seq_length, video_length)  # Truncate if longer than max_seq_length\n",
    "            for j in range(length):\n",
    "              # Extract features from a single frame using the feature extractor model\n",
    "              temp_frame_features[i, j, :] = feature_extractor.predict(batch[None, j, :])\n",
    "            # Create a mask for the current video (1 for valid frames, 0 for padding)\n",
    "            temp_frame_mask[i, :length] = 1\n",
    "        # Store the features and mask for the current video in the main arrays\n",
    "        frame_features[idx, :] = temp_frame_features.squeeze()\n",
    "        frame_masks[idx, :] = temp_frame_mask.squeeze()\n",
    "    # Return the preprocessed video features and corresponding labels\n",
    "    return (frame_features, frame_masks), labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "a6975bea",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(360, 3) (40, 3)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# Split the training data into training and testing sets\n",
    "Train_set, Test_set = train_test_split(train_metadata, \n",
    "                                       test_size=0.1, \n",
    "                                       random_state=42, \n",
    "                                       stratify=train_metadata['label'])\n",
    "\n",
    "# Print the shapes of the resulting training and testing sets\n",
    "print(Train_set.shape, Test_set.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "f5eb3411",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Frame features in train set: (360, 40, 2048)\n",
      "Frame masks in train set: (360, 40)\n"
     ]
    }
   ],
   "source": [
    "# Preprocess, extract features and create masks from all videos from train set\n",
    "#train_data is a NumPy array containing preprocessed video features for the training set.\n",
    "# train_labels is a NumPy array containing labels (0 - real, 1 - fake) for the training set videos.\n",
    "train_data, train_labels = preprocess_videos(Train_set, \"train\")\n",
    "\n",
    "# Preprocess, extract features and create masks from all videos from test set\n",
    "#test_data is a NumPy array containing preprocessed video features for the test set.\n",
    "# test_labels is a NumPy array containing labels (0 - real, 1 - fake) for the test set videos.\n",
    "test_data, test_labels = preprocess_videos(Test_set, \"test\")\n",
    "\n",
    "# Print the shapes of training data components\n",
    "# train_data[0] contains features and train_data[1] contains masks\n",
    "print(f\"Frame features in train set: {train_data[0].shape}\")\n",
    "print(f\"Frame masks in train set: {train_data[1].shape}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "e4ea318a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False])"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#let us see what a mask looks like\n",
    "train_data[1][2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "49d42efb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"functional_4\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"functional_4\"\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Layer (type)                  </span>┃<span style=\"font-weight: bold\"> Output Shape              </span>┃<span style=\"font-weight: bold\">         Param # </span>┃<span style=\"font-weight: bold\"> Connected to               </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│ input_layer_16 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)   │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">40</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">2048</span>)          │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ input_layer_17 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)   │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">40</span>)                │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ gru_8 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GRU</span>)                   │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">40</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">16</span>)            │          <span style=\"color: #00af00; text-decoration-color: #00af00\">99,168</span> │ input_layer_16[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>],      │\n",
       "│                               │                           │                 │ input_layer_17[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]       │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ gru_9 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GRU</span>)                   │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">8</span>)                 │             <span style=\"color: #00af00; text-decoration-color: #00af00\">624</span> │ gru_8[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]                │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dropout_4 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>)           │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">8</span>)                 │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ gru_9[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]                │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dense_11 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)              │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">8</span>)                 │              <span style=\"color: #00af00; text-decoration-color: #00af00\">72</span> │ dropout_4[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]            │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dense_12 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)              │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1</span>)                 │               <span style=\"color: #00af00; text-decoration-color: #00af00\">9</span> │ dense_11[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]             │\n",
       "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                 \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape             \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m        Param #\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mConnected to              \u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│ input_layer_16 (\u001b[38;5;33mInputLayer\u001b[0m)   │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m40\u001b[0m, \u001b[38;5;34m2048\u001b[0m)          │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ input_layer_17 (\u001b[38;5;33mInputLayer\u001b[0m)   │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m40\u001b[0m)                │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ gru_8 (\u001b[38;5;33mGRU\u001b[0m)                   │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m40\u001b[0m, \u001b[38;5;34m16\u001b[0m)            │          \u001b[38;5;34m99,168\u001b[0m │ input_layer_16[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m],      │\n",
       "│                               │                           │                 │ input_layer_17[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]       │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ gru_9 (\u001b[38;5;33mGRU\u001b[0m)                   │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m8\u001b[0m)                 │             \u001b[38;5;34m624\u001b[0m │ gru_8[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]                │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dropout_4 (\u001b[38;5;33mDropout\u001b[0m)           │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m8\u001b[0m)                 │               \u001b[38;5;34m0\u001b[0m │ gru_9[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]                │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dense_11 (\u001b[38;5;33mDense\u001b[0m)              │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m8\u001b[0m)                 │              \u001b[38;5;34m72\u001b[0m │ dropout_4[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]            │\n",
       "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
       "│ dense_12 (\u001b[38;5;33mDense\u001b[0m)              │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m)                 │               \u001b[38;5;34m9\u001b[0m │ dense_11[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]             │\n",
       "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">99,873</span> (390.13 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m99,873\u001b[0m (390.13 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">99,873</span> (390.13 KB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m99,873\u001b[0m (390.13 KB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Define model inputs\n",
    "frame_features_input = keras.Input((max_seq_length, num_features))  # Input for video features\n",
    "mask_input = keras.Input((max_seq_length,), dtype=\"bool\")          # Input for frame masks\n",
    "# mask_input takes frame masks containing boolean values, True for valid frames, False for padding\n",
    "\n",
    "\n",
    "\n",
    "# First GRU layer with 16 units, returning entire output sequence for further processing by next GRU layer\n",
    "# mask=mask_input to utilize the masking functionality based on the provided frame masks.\n",
    "x = keras.layers.GRU(16, return_sequences=True)(frame_features_input, mask=mask_input)\n",
    "# Masking (https://keras.io/api/layers/recurrent_layers/gru/) allows the GRU layer to handle sequences with variable lengths \n",
    "# by ignoring padded elements based on the mask.\n",
    "\n",
    "# Second GRU layer with 8 units processes the output from the first GRU layer\n",
    "x = keras.layers.GRU(8)(x)\n",
    "\n",
    "# Dropout layer with 40% dropout rate for regularization\n",
    "#randomly drop 40% of the units' outputs during training to prevent overfitting.\n",
    "x = keras.layers.Dropout(0.4)(x)\n",
    "\n",
    "# Dense layer with 8 units and ReLU activation for non-linearity\n",
    "x = keras.layers.Dense(8, activation=\"relu\")(x)\n",
    "\n",
    "# Output layer with 1 unit and sigmoid activation for binary classification (fake/real)\n",
    "output = keras.layers.Dense(1, activation=\"sigmoid\")(x)\n",
    "\n",
    "# Create the model with specified inputs and output\n",
    "model = keras.Model([frame_features_input, mask_input], output)\n",
    "\n",
    "# Compile the model with binary crossentropy loss, Adam optimizer, and accuracy metric\n",
    "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
    "\n",
    "# Print a summary of the model architecture\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "dc2e1fe9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 27ms/step - accuracy: 0.7796 - loss: 0.6899 - val_accuracy: 0.8000 - val_loss: 0.6811\n",
      "Epoch 2/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8145 - loss: 0.6775 - val_accuracy: 0.8000 - val_loss: 0.6697\n",
      "Epoch 3/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8180 - loss: 0.6654 - val_accuracy: 0.8000 - val_loss: 0.6589\n",
      "Epoch 4/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8225 - loss: 0.6534 - val_accuracy: 0.8000 - val_loss: 0.6485\n",
      "Epoch 5/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 12ms/step - accuracy: 0.7403 - loss: 0.6561 - val_accuracy: 0.8000 - val_loss: 0.6395\n",
      "Epoch 6/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8324 - loss: 0.6304 - val_accuracy: 0.8000 - val_loss: 0.6297\n",
      "Epoch 7/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7906 - loss: 0.6299 - val_accuracy: 0.8000 - val_loss: 0.6214\n",
      "Epoch 8/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8398 - loss: 0.6082 - val_accuracy: 0.8000 - val_loss: 0.6129\n",
      "Epoch 9/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8015 - loss: 0.6106 - val_accuracy: 0.8000 - val_loss: 0.6055\n",
      "Epoch 10/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8235 - loss: 0.5955 - val_accuracy: 0.8000 - val_loss: 0.5983\n",
      "Epoch 11/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 25ms/step - accuracy: 0.7908 - loss: 0.6002 - val_accuracy: 0.8000 - val_loss: 0.5917\n",
      "Epoch 12/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8191 - loss: 0.5820 - val_accuracy: 0.8000 - val_loss: 0.5850\n",
      "Epoch 13/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8538 - loss: 0.5595 - val_accuracy: 0.8000 - val_loss: 0.5789\n",
      "Epoch 14/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8249 - loss: 0.5656 - val_accuracy: 0.8000 - val_loss: 0.5734\n",
      "Epoch 15/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7908 - loss: 0.5768 - val_accuracy: 0.8000 - val_loss: 0.5684\n",
      "Epoch 16/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7863 - loss: 0.5746 - val_accuracy: 0.8000 - val_loss: 0.5636\n",
      "Epoch 17/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8155 - loss: 0.5534 - val_accuracy: 0.8000 - val_loss: 0.5587\n",
      "Epoch 18/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.8271 - loss: 0.5415 - val_accuracy: 0.8000 - val_loss: 0.5546\n",
      "Epoch 19/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8200 - loss: 0.5410 - val_accuracy: 0.8000 - val_loss: 0.5504\n",
      "Epoch 20/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8044 - loss: 0.5467 - val_accuracy: 0.8000 - val_loss: 0.5468\n",
      "Epoch 21/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 26ms/step - accuracy: 0.8148 - loss: 0.5359 - val_accuracy: 0.8000 - val_loss: 0.5432\n",
      "Epoch 22/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8092 - loss: 0.5360 - val_accuracy: 0.8000 - val_loss: 0.5400\n",
      "Epoch 23/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8032 - loss: 0.5368 - val_accuracy: 0.8000 - val_loss: 0.5368\n",
      "Epoch 24/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8102 - loss: 0.5286 - val_accuracy: 0.8000 - val_loss: 0.5342\n",
      "Epoch 25/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7984 - loss: 0.5348 - val_accuracy: 0.8000 - val_loss: 0.5315\n",
      "Epoch 26/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 15ms/step - accuracy: 0.8156 - loss: 0.5183 - val_accuracy: 0.8000 - val_loss: 0.5290\n",
      "Epoch 27/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7759 - loss: 0.5482 - val_accuracy: 0.8000 - val_loss: 0.5269\n",
      "Epoch 28/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8213 - loss: 0.5084 - val_accuracy: 0.8000 - val_loss: 0.5246\n",
      "Epoch 29/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8171 - loss: 0.5095 - val_accuracy: 0.8000 - val_loss: 0.5229\n",
      "Epoch 30/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.8217 - loss: 0.5031 - val_accuracy: 0.8000 - val_loss: 0.5209\n",
      "Epoch 31/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 21ms/step - accuracy: 0.7939 - loss: 0.5260 - val_accuracy: 0.8000 - val_loss: 0.5192\n",
      "Epoch 32/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 50ms/step - accuracy: 0.8044 - loss: 0.5147 - val_accuracy: 0.8000 - val_loss: 0.5177\n",
      "Epoch 33/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 23ms/step - accuracy: 0.8200 - loss: 0.4984 - val_accuracy: 0.8000 - val_loss: 0.5162\n",
      "Epoch 34/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8054 - loss: 0.5105 - val_accuracy: 0.8000 - val_loss: 0.5147\n",
      "Epoch 35/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8005 - loss: 0.5139 - val_accuracy: 0.8000 - val_loss: 0.5136\n",
      "Epoch 36/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8363 - loss: 0.4771 - val_accuracy: 0.8000 - val_loss: 0.5124\n",
      "Epoch 37/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7725 - loss: 0.5400 - val_accuracy: 0.8000 - val_loss: 0.5114\n",
      "Epoch 38/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 17ms/step - accuracy: 0.7727 - loss: 0.5392 - val_accuracy: 0.8000 - val_loss: 0.5104\n",
      "Epoch 39/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7930 - loss: 0.5174 - val_accuracy: 0.8000 - val_loss: 0.5096\n",
      "Epoch 40/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 15ms/step - accuracy: 0.8012 - loss: 0.5080 - val_accuracy: 0.8000 - val_loss: 0.5087\n",
      "Epoch 41/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 12ms/step - accuracy: 0.7798 - loss: 0.5301 - val_accuracy: 0.8000 - val_loss: 0.5078\n",
      "Epoch 42/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 19ms/step - accuracy: 0.8088 - loss: 0.4980 - val_accuracy: 0.8000 - val_loss: 0.5072\n",
      "Epoch 43/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8079 - loss: 0.4983 - val_accuracy: 0.8000 - val_loss: 0.5065\n",
      "Epoch 44/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8138 - loss: 0.4909 - val_accuracy: 0.8000 - val_loss: 0.5060\n",
      "Epoch 45/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.8203 - loss: 0.4829 - val_accuracy: 0.8000 - val_loss: 0.5054\n",
      "Epoch 46/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7908 - loss: 0.5158 - val_accuracy: 0.8000 - val_loss: 0.5049\n",
      "Epoch 47/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 13ms/step - accuracy: 0.7835 - loss: 0.5239 - val_accuracy: 0.8000 - val_loss: 0.5045\n",
      "Epoch 48/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 16ms/step - accuracy: 0.8323 - loss: 0.4667 - val_accuracy: 0.8000 - val_loss: 0.5040\n",
      "Epoch 49/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 15ms/step - accuracy: 0.8208 - loss: 0.4793 - val_accuracy: 0.8000 - val_loss: 0.5036\n",
      "Epoch 50/50\n",
      "\u001b[1m45/45\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 16ms/step - accuracy: 0.8625 - loss: 0.4291 - val_accuracy: 0.8000 - val_loss: 0.5032\n"
     ]
    }
   ],
   "source": [
    "# Define ModelCheckpoint callback\n",
    "checkpoint = keras.callbacks.ModelCheckpoint(\n",
    "    filepath='./videoclassification.weights.h5',   # Path to save weights\n",
    "    save_weights_only=True,                         # Save only model weights\n",
    "    save_best_only=True                             # Save only the model with best validation performance\n",
    ")\n",
    "\n",
    "# Train the model\n",
    "# The 'history' variable returned by model.fit() stores the training and validation loss (or other metrics) across epochs.\n",
    "history = model.fit(\n",
    "    [train_data[0], train_data[1]],                  # Training features and masks\n",
    "    train_labels,                                    # Training labels\n",
    "    validation_data=([test_data[0], test_data[1]],   # Validation features and masks\n",
    "                     test_labels),                   # Validation labels\n",
    "    callbacks=[checkpoint],                          # Include ModelCheckpoint callback to use model weight saving \n",
    "    epochs = no_of_epochs,                           # Number of training epochs\n",
    "    batch_size=8                                     # Batch size for training\n",
    ")\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "6deb62b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0wAAAHDCAYAAAAX5JqTAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAC0UUlEQVR4nOzdeVxUZfvH8c8wbKICLgioKO67aJjkklqhqGW5VKbmQi5lLiltWm5Z6fP8LPPJLMsyLTVNU7M0N9IW9zDNDPcFN9wBRdlm5vcHMjUBygA6gN/36zWv4sx97nOdEzHnmvs+122wWCwWREREREREJBMnRwcgIiIiIiJSUClhEhERERERyYYSJhERERERkWwoYRIREREREcmGEiYREREREZFsKGESERERERHJhhImERERERGRbChhEhERERERyYYSJhERERERkWwoYbpL9evXj8DAwFztO2HCBAwGQ/4GVMAcO3YMg8HAnDlz7vixDQYDEyZMsP48Z84cDAYDx44du+W+gYGB9OvXL1/jycvvioiII+mz7ub0Wfc3fdbJzShhKmAMBkOOXhs3bnR0qHe94cOHYzAYOHToULZtXn/9dQwGA3/88ccdjMx+p0+fZsKECezatcvRoWQpOjoag8GAu7s7cXFxjg5HRPJIn3WFhz7rbq+MpPWdd95xdChyE86ODkBsffnllzY/f/HFF6xbty7T9jp16uTpOLNmzcJsNudq3zFjxjBq1Kg8Hb8o6NWrF9OnT2fBggWMGzcuyzZfffUVDRo0oGHDhrk+Tu/evXnqqadwc3PLdR+3cvr0ad544w0CAwNp1KiRzXt5+V3JL/PmzcPPz4/Lly+zZMkSBgwY4NB4RCRv9FlXeOizTkQJU4Hz9NNP2/y8detW1q1bl2n7v127dg0PD48cH8fFxSVX8QE4Ozvj7KxfnZCQEKpXr85XX32V5YfIli1bOHr0KP/5z3/ydByj0YjRaMxTH3mRl9+V/GCxWFiwYAE9e/bk6NGjzJ8/v8AmTImJiRQvXtzRYYgUePqsKzz0WSeiKXmFUps2bahfvz5RUVG0atUKDw8PXnvtNQC+/fZbHn74YcqXL4+bmxvVqlXjzTffxGQy2fTx77m6/xwS/uSTT6hWrRpubm7ce++97Nixw2bfrOZ1GwwGhg4dyvLly6lfvz5ubm7Uq1eP1atXZ4p/48aNNGnSBHd3d6pVq8bHH3+c47niv/zyC0888QSVKlXCzc2NgIAARo4cyfXr1zOdX4kSJTh16hSdO3emRIkS+Pj48NJLL2W6FnFxcfTr1w8vLy+8vb3p27dvjqd99erVi3379rFz585M7y1YsACDwUCPHj1ISUlh3LhxBAcH4+XlRfHixbn//vvZsGHDLY+R1bxui8XCW2+9RcWKFfHw8OCBBx5g7969mfa9dOkSL730Eg0aNKBEiRJ4enrSoUMHdu/ebW2zceNG7r33XgDCw8OtU2Ey5rRnNa87MTGRF198kYCAANzc3KhVqxbvvPMOFovFpp09vxfZ2bRpE8eOHeOpp57iqaee4ueff+bkyZOZ2pnNZv73v//RoEED3N3d8fHxoX379vz222827ebNm0fTpk3x8PCgVKlStGrVirVr19rE/M959Rn+PWc+47/LTz/9xPPPP0+5cuWoWLEiAMePH+f555+nVq1aFCtWjDJlyvDEE09kOTc/Li6OkSNHEhgYiJubGxUrVqRPnz5cuHCBq1evUrx4cV544YVM+508eRKj0cjkyZNzeCVFChd91umz7m76rLuVc+fO0b9/f3x9fXF3dycoKIi5c+dmardw4UKCg4MpWbIknp6eNGjQgP/973/W91NTU3njjTeoUaMG7u7ulClThpYtW7Ju3bp8i7Uo0lcnhdTFixfp0KEDTz31FE8//TS+vr5A+h+cEiVKEBERQYkSJfjxxx8ZN24cCQkJTJky5Zb9LliwgCtXrvDss89iMBj4v//7P7p27cqRI0du+e3Lr7/+ytKlS3n++ecpWbIk77//Pt26dSMmJoYyZcoA8Pvvv9O+fXv8/f154403MJlMTJw4ER8fnxyd9+LFi7l27RqDBw+mTJkybN++nenTp3Py5EkWL15s09ZkMhEWFkZISAjvvPMO69ev591336VatWoMHjwYSP9j/Nhjj/Hrr7/y3HPPUadOHZYtW0bfvn1zFE+vXr144403WLBgAffcc4/Nsb/++mvuv/9+KlWqxIULF/j000/p0aMHAwcO5MqVK3z22WeEhYWxffv2TFMDbmXcuHG89dZbdOzYkY4dO7Jz507atWtHSkqKTbsjR46wfPlynnjiCapUqcLZs2f5+OOPad26NX/99Rfly5enTp06TJw4kXHjxjFo0CDuv/9+AJo3b57lsS0WC48++igbNmygf//+NGrUiDVr1vDyyy9z6tQp3nvvPZv2Ofm9uJn58+dTrVo17r33XurXr4+HhwdfffUVL7/8sk27/v37M2fOHDp06MCAAQNIS0vjl19+YevWrTRp0gSAN954gwkTJtC8eXMmTpyIq6sr27Zt48cff6Rdu3Y5vv7/9Pzzz+Pj48O4ceNITEwEYMeOHWzevJmnnnqKihUrcuzYMT766CPatGnDX3/9Zf2G/OrVq9x///1ER0fzzDPPcM8993DhwgVWrFjByZMnadSoEV26dGHRokVMnTrV5tvXr776CovFQq9evXIVt0hhoM86fdbdLZ91N3P9+nXatGnDoUOHGDp0KFWqVGHx4sX069ePuLg465dq69ato0ePHjz00EP897//BdKfAd60aZO1zYQJE5g8eTIDBgygadOmJCQk8Ntvv7Fz507atm2bpziLNIsUaEOGDLH8+z9T69atLYBl5syZmdpfu3Yt07Znn33W4uHhYUlKSrJu69u3r6Vy5crWn48ePWoBLGXKlLFcunTJuv3bb7+1AJbvvvvOum38+PGZYgIsrq6ulkOHDlm37d692wJYpk+fbt3WqVMni4eHh+XUqVPWbQcPHrQ4Oztn6jMrWZ3f5MmTLQaDwXL8+HGb8wMsEydOtGnbuHFjS3BwsPXn5cuXWwDL//3f/1m3paWlWe6//34LYPn8889vGdO9995rqVixosVkMlm3rV692gJYPv74Y2ufycnJNvtdvnzZ4uvra3nmmWdstgOW8ePHW3/+/PPPLYDl6NGjFovFYjl37pzF1dXV8vDDD1vMZrO13WuvvWYBLH379rVuS0pKsonLYkn/b+3m5mZzbXbs2JHt+f77dyXjmr311ls27R5//HGLwWCw+R3I6e9FdlJSUixlypSxvP7669ZtPXv2tAQFBdm0+/HHHy2AZfjw4Zn6yLhGBw8etDg5OVm6dOmS6Zr88zr++/pnqFy5ss21zfjv0rJlS0taWppN26x+T7ds2WIBLF988YV127hx4yyAZenSpdnGvWbNGgtg+eGHH2zeb9iwoaV169aZ9hMpjPRZd+vz02dduqL2WZfxOzllypRs20ybNs0CWObNm2fdlpKSYmnWrJmlRIkSloSEBIvFYrG88MILFk9Pz0yfSf8UFBRkefjhh28ak2SmKXmFlJubG+Hh4Zm2FytWzPrvV65c4cKFC9x///1cu3aNffv23bLf7t27U6pUKevPGd/AHDly5Jb7hoaGUq1aNevPDRs2xNPT07qvyWRi/fr1dO7cmfLly1vbVa9enQ4dOtyyf7A9v8TERC5cuEDz5s2xWCz8/vvvmdo/99xzNj/ff//9NueyatUqnJ2drd/CQfo86mHDhuUoHkifi3/y5El+/vln67YFCxbg6urKE088Ye3T1dUVSJ86dunSJdLS0mjSpEmWUxxuZv369aSkpDBs2DCbqR0jRozI1NbNzQ0np/T/zU0mExcvXqREiRLUqlXL7uNmWLVqFUajkeHDh9tsf/HFF7FYLPzwww8222/1e3EzP/zwAxcvXqRHjx7WbT169GD37t020zK++eYbDAYD48ePz9RHxjVavnw5ZrOZcePGWa/Jv9vkxsCBAzPNu//n72lqaioXL16kevXqeHt721z3b775hqCgILp06ZJt3KGhoZQvX5758+db3/vzzz/5448/bvm8h0hhp886fdbdDZ91OYnFz8/P5rPQxcWF4cOHc/XqVX766ScAvL29SUxMvOn0Om9vb/bu3cvBgwfzHNfdRAlTIVWhQgXrH6V/2rt3L126dMHLywtPT098fHysN1Xx8fG37LdSpUo2P2d8oFy+fNnufTP2z9j33LlzXL9+nerVq2dql9W2rMTExNCvXz9Kly5tnavdunVrIPP5ZTzHkl08kP6sib+/PyVKlLBpV6tWrRzFA/DUU09hNBpZsGABAElJSSxbtowOHTrYfCDPnTuXhg0bWucM+/j4sHLlyhz9d/mn48ePA1CjRg2b7T4+PjbHg/QPrPfee48aNWrg5uZG2bJl8fHx4Y8//rD7uP88fvny5SlZsqTN9oxqVhnxZbjV78XNzJs3jypVquDm5sahQ4c4dOgQ1apVw8PDwyaBOHz4MOXLl6d06dLZ9nX48GGcnJyoW7fuLY9rjypVqmTadv36dcaNG2ed955x3ePi4myu++HDh6lfv/5N+3dycqJXr14sX76ca9euAenTFN3d3a03KSJFlT7r9Fl3N3zW5SSWGjVqZPqy79+xPP/889SsWZMOHTpQsWJFnnnmmUzPUU2cOJG4uDhq1qxJgwYNePnllwt8OfiCQAlTIfXPb58yxMXF0bp1a3bv3s3EiRP57rvvWLdunXUea07KZWZXocbyrwcc83vfnDCZTLRt25aVK1fy6quvsnz5ctatW2d9YPPf53enqu2UK1eOtm3b8s0335Camsp3333HlStXbJ4tmTdvHv369aNatWp89tlnrF69mnXr1vHggw/e1jKmkyZNIiIiglatWjFv3jzWrFnDunXrqFev3h0rn5rb34uEhAS+++47jh49So0aNayvunXrcu3aNRYsWJBvv1s58e8HqDNk9f/isGHDePvtt3nyySf5+uuvWbt2LevWraNMmTK5uu59+vTh6tWrLF++3Fo18JFHHsHLy8vuvkQKE33W6bMuJwrzZ11+KleuHLt27WLFihXW5686dOhg86xaq1atOHz4MLNnz6Z+/fp8+umn3HPPPXz66ad3LM7CSEUfipCNGzdy8eJFli5dSqtWrazbjx496sCo/lauXDnc3d2zXPzuZgviZdizZw8HDhxg7ty59OnTx7o9L5VdKleuTGRkJFevXrX55m3//v129dOrVy9Wr17NDz/8wIIFC/D09KRTp07W95csWULVqlVZunSpzdSCrKaQ5SRmgIMHD1K1alXr9vPnz2f6JmvJkiU88MADfPbZZzbb4+LiKFu2rPVne6akVa5cmfXr13PlyhWbb94ypsFkxJdXS5cuJSkpiY8++sgmVkj/7zNmzBg2bdpEy5YtqVatGmvWrOHSpUvZjjJVq1YNs9nMX3/9ddMHj0uVKpWpclRKSgpnzpzJcexLliyhb9++vPvuu9ZtSUlJmfqtVq0af/755y37q1+/Po0bN2b+/PlUrFiRmJgYpk+fnuN4RIoSfdbZT5916QriZ11OY/njjz8wm802o0xZxeLq6kqnTp3o1KkTZrOZ559/no8//pixY8daRzhLly5NeHg44eHhXL16lVatWjFhwoQCu2RHQaARpiIk49uNf36bkZKSwocffuiokGwYjUZCQ0NZvnw5p0+ftm4/dOhQprnA2e0PtudnsVhsymXaq2PHjqSlpfHRRx9Zt5lMJrtvRjt37oyHhwcffvghP/zwA127dsXd3f2msW/bto0tW7bYHXNoaCguLi5Mnz7dpr9p06Zlams0GjN9u7V48WJOnTplsy1j7aCclJjt2LEjJpOJDz74wGb7e++9h8FgyPEc/VuZN28eVatW5bnnnuPxxx+3eb300kuUKFHCOi2vW7duWCwW3njjjUz9ZJx/586dcXJyYuLEiZm+cfznNapWrZrNHH2ATz75JNsRpqxkdd2nT5+eqY9u3bqxe/duli1blm3cGXr37s3atWuZNm0aZcqUybfrLFLY6LPOfvqsS1cQP+tyomPHjsTGxrJo0SLrtrS0NKZPn06JEiWs0zUvXrxos5+Tk5N1MeHk5OQs25QoUYLq1atb35esaYSpCGnevDmlSpWib9++DB8+HIPBwJdffnlHh4NvZcKECaxdu5YWLVowePBg6x+j+vXrs2vXrpvuW7t2bapVq8ZLL73EqVOn8PT05JtvvsnT/OBOnTrRokULRo0axbFjx6hbty5Lly61e85ziRIl6Ny5s3Vu979LPT/yyCMsXbqULl268PDDD3P06FFmzpxJ3bp1uXr1ql3HylhjY/LkyTzyyCN07NiR33//nR9++CHTSMwjjzzCxIkTCQ8Pp3nz5uzZs4f58+fbfFsH6UmCt7c3M2fOpGTJkhQvXpyQkJAsn8/p1KkTDzzwAK+//jrHjh0jKCiItWvX8u233zJixAibh15z6/Tp02zYsCHTw7YZ3NzcCAsLY/Hixbz//vs88MAD9O7dm/fff5+DBw/Svn17zGYzv/zyCw888ABDhw6levXqvP7667z55pvcf//9dO3aFTc3N3bs2EH58uWt6xkNGDCA5557jm7dutG2bVt2797NmjVrMl3bm3nkkUf48ssv8fLyom7dumzZsoX169dnKi378ssvs2TJEp544gmeeeYZgoODuXTpEitWrGDmzJkEBQVZ2/bs2ZNXXnmFZcuWMXjwYC2yKHctfdbZT5916QraZ90/RUZGkpSUlGl7586dGTRoEB9//DH9+vUjKiqKwMBAlixZwqZNm5g2bZp1BGzAgAFcunSJBx98kIoVK3L8+HGmT59Oo0aNrM871a1blzZt2hAcHEzp0qX57bffWLJkCUOHDs3X8yly7kAlPsmD7Eqt1qtXL8v2mzZtstx3332WYsWKWcqXL2955ZVXrGWJN2zYYG2XXanVrMpa8q/Sn9mVWh0yZEimff9ditlisVgiIyMtjRs3tri6ulqqVatm+fTTTy0vvviixd3dPZur8Le//vrLEhoaailRooSlbNmyloEDB1pLd/6zTGjfvn0txYsXz7R/VrFfvHjR0rt3b4unp6fFy8vL0rt3b8vvv/+e41KrGVauXGkBLP7+/lmWrZ40aZKlcuXKFjc3N0vjxo0t33//fab/DhbLrUutWiwWi8lksrzxxhsWf39/S7FixSxt2rSx/Pnnn5mud1JSkuXFF1+0tmvRooVly5YtltatW2cqSf3tt99a6tatay17m3HuWcV45coVy8iRIy3ly5e3uLi4WGrUqGGZMmWKTenXjHPJ6e/FP7377rsWwBIZGZltmzlz5lgAy7fffmuxWNLL2U6ZMsVSu3Zti6urq8XHx8fSoUMHS1RUlM1+s2fPtjRu3Nji5uZmKVWqlKV169aWdevWWd83mUyWV1991VK2bFmLh4eHJSwszHLo0KFsy4rv2LEjU2yXL1+2hIeHW8qWLWspUaKEJSwszLJv374sz/vixYuWoUOHWipUqGBxdXW1VKxY0dK3b1/LhQsXMvXbsWNHC2DZvHlzttdFpDDSZ50tfdalK+qfdRbL37+T2b2+/PJLi8VisZw9e9b6ueLq6mpp0KBBpv9uS5YssbRr185Srlw5i6urq6VSpUqWZ5991nLmzBlrm7feesvStGlTi7e3t6VYsWKW2rVrW95++21LSkrKTeO82xkslgL0lYzctTp37qwylyK30KVLF/bs2ZOj5yBEpODRZ51I4aRnmOSOu379us3PBw8eZNWqVbRp08YxAYkUAmfOnGHlypX07t3b0aGISA7os06k6NAIk9xx/v7+9OvXj6pVq3L8+HE++ugjkpOT+f333zOttyBytzt69CibNm3i008/ZceOHRw+fBg/Pz9HhyUit6DPOpGiQ0Uf5I5r3749X331FbGxsbi5udGsWTMmTZqkDxCRLPz000+Eh4dTqVIl5s6dq2RJpJDQZ51I0aERJhERERERkWzoGSYREREREZFsKGESERERERHJxl3zDJPZbOb06dOULFkSg8Hg6HBERO4qFouFK1euUL58eZyc9F1dBn02iYg4hj2fS3dNwnT69GkCAgIcHYaIyF3txIkTVKxY0dFhFBj6bBIRcaycfC7dNQlTyZIlgfSL4unp6eBoRETuLgkJCQQEBFj/Fks6fTaJiDiGPZ9Ld03ClDHVwdPTUx9KIiIOomlntvTZJCLiWDn5XNJEchERERERkWwoYRIREREREcmGEiYREREREZFs3DXPMImIiIhIwWQymUhNTXV0GFLEuLq65stSFkqYRERERMQhLBYLsbGxxMXFOToUKYKcnJyoUqUKrq6ueepHCZOIiIiIOERGslSuXDk8PDxUSVPy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",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# plot training accuracy, validation accuracy, training loss and validation loss over 25 epochs\n",
    "acc = history.history['accuracy']\n",
    "val_acc = history.history['val_accuracy']\n",
    "\n",
    "loss = history.history['loss']\n",
    "val_loss = history.history['val_loss']\n",
    "\n",
    "epochs = 50\n",
    "epochs_range = range(epochs)\n",
    "\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.plot(epochs_range, acc, label='Training Accuracy')\n",
    "plt.plot(epochs_range, val_acc, label='Validation Accuracy')\n",
    "plt.legend(loc='lower right')\n",
    "plt.title('Training and Validation Accuracy')\n",
    "\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.plot(epochs_range, loss, label='Training Loss')\n",
    "plt.plot(epochs_range, val_loss, label='Validation Loss')\n",
    "plt.legend(loc='upper right')\n",
    "plt.title('Training and Validation Loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "945d414c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m2/2\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0s/step - accuracy: 0.8042 - loss: 0.4982   \n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.5032228231430054, 0.800000011920929]"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Evaluate the trained model on test data\n",
    "model.evaluate([test_data[0], test_data[1]],test_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "e3f5315f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test video path: nthpnwylxo.mp4\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 2s/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 46ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 38ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 34ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 38ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 42ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 45ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 32ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 34ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 35ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 47ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 31ms/step\n",
      "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 281ms/step\n",
      "The predicted class of the video is FAKE (probability: 0.77)\n"
     ]
    }
   ],
   "source": [
    "def preprocess_a_testvideo(frames):\n",
    "    \"\"\"\n",
    "    This function preprocesses a single video for prediction.\n",
    "\n",
    "    Args:\n",
    "      frames: A NumPy array containing frames of a video.\n",
    "\n",
    "    Returns:\n",
    "      tuple: A tuple containing two elements:\n",
    "          - features (numpy.ndarray): A 3D array of video features, \n",
    "              shaped (1, max_seq_length, num_features).\n",
    "          - mask (numpy.ndarray): A 2D array of frame masks, \n",
    "              shaped (1, max_seq_length).\n",
    "    \"\"\"\n",
    "\n",
    "    # Add a batch dimension to the frames\n",
    "    frames = frames[None, ...]\n",
    "    # Initialize arrays for features and mask of the video\n",
    "    frame_mask = np.zeros(shape=(1, max_seq_length,), dtype=\"bool\")\n",
    "    frame_features = np.zeros(shape=(1, max_seq_length, num_features), dtype=\"float32\")\n",
    "\n",
    "    # Process each frame in the video\n",
    "    for i, batch in enumerate(frames):\n",
    "        video_length = batch.shape[0]\n",
    "        length = min(max_seq_length, video_length)  # Truncate if longer than max_seq_length\n",
    "        for j in range(length):\n",
    "            # Extract features from a single frame using the feature extractor model\n",
    "            frame_features[i, j, :] = feature_extractor.predict(batch[None, j, :])\n",
    "        # Create a mask for the video (1 for valid frames, 0 for padding)\n",
    "        frame_mask[i, :length] = 1\n",
    "\n",
    "    # Return the preprocessed video features and mask\n",
    "    return frame_features, frame_mask\n",
    "\n",
    "\n",
    "def classify_a_testvideo(path):\n",
    "    \"\"\"\n",
    "    This function predicts the class (fake or real) for a given video path.\n",
    "\n",
    "    Args:\n",
    "      path (str): Path to the video file.\n",
    "\n",
    "    Returns:\n",
    "      float: Predicted probability of the video being fake (between 0 and 1).\n",
    "    \"\"\"\n",
    "\n",
    "    # Load frames from the video\n",
    "    frames = load_video(os.path.join(data_dir, test_dir, path))\n",
    "\n",
    "    # Preprocess the video (features and mask)\n",
    "    frame_features, frame_mask = preprocess_a_testvideo(frames)\n",
    "\n",
    "    # Predict the class using the trained model\n",
    "    prediction = model.predict([frame_features, frame_mask])[0]\n",
    "\n",
    "    # Return the predicted probability for the fake class\n",
    "    return prediction\n",
    "\n",
    "\n",
    "# Select a random test video path\n",
    "test_video = np.random.choice(test_videos[\"video\"].values.tolist())\n",
    "print(f\"Test video path: {test_video}\")\n",
    "\n",
    "# Predict the class (fake or real) for the chosen video\n",
    "prediction = classify_a_testvideo(test_video)\n",
    "\n",
    "if prediction >= 0.5:\n",
    "    print(f'The predicted class of the video is FAKE (probability: {prediction[0]:.2f})')\n",
    "else:\n",
    "    print(f'The predicted class of the video is REAL (probability: {1-prediction[0]:.2f})')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7bf4a0d6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (pytorch_cuda)",
   "language": "python",
   "name": "pytorch_cuda"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
